<?php

namespace App\Services\Auth;

use App\Entities\Auth\Module;
use App\Libraries\Common\Tree;
use App\Repositories\Auth\ModuleRepository;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use App\Libraries\Common\PinqHelper;
use Pinq\Traversable;

class ModuleService
{
    use PinqHelper;

    protected $repository;
    protected $modules = null;

    public function __construct(ModuleRepository $repository)
    {
        $this->repository = $repository;
    }

    public function getPageList($is_web = true)
    {
        try {
            $request = request();
            $modules = Traversable::from($this->repository->getRedisData());
            if ($request->get('parent_id')) {
                $parent_id = $request->get('parent_id');
                $modules = $modules->where(function ($item) use ($parent_id) {
                    return $item->parent_id == $parent_id;
                });
            }
            $modules = $modules->orderByAscending(function ($item) {
                return $item->sort_code;
            });
            $data = $this->Pagelist($is_web, $modules);

            return $data;
        } catch (Exception $ex) {
            Log::error('Module getPageList Error', [$ex->getMessage()]);

            return null;
        }
    }

    public function create($data)
    {
        try {
            $module = new Module($data);
            $module->encode = strtoupper(preg_match('/^['.chr(0xa1).'-'.chr(0xff).']+$/', $module->full_name) ? $module->full_name : pinyin_abbr($module->full_name));
            $this->repository->SaveData($module);

            $this->repository->resetRedisData();

            return true;
        } catch (Exception $ex) {
            Log::error('Module Create Error', [$ex->getMessage()]);

            return false;
        }
    }

    public function update($id, $data)
    {
        try {
            $module = new Module($data);
            $module->encode = strtoupper(preg_match('/^['.chr(0xa1).'-'.chr(0xff).']+$/', $module->full_name) ? $module->full_name : pinyin_abbr($module->full_name));
            $this->repository->SaveData($module, $id);
            $this->repository->resetRedisData();

            return true;
        } catch (Exception $ex) {
            Log::error('Module Update id="'.$id.'" Error', [$ex->getMessage()]);

            return false;
        }
    }

    public function show($id)
    {
        try {
            $modules = Traversable::from($this->repository->getRedisData());

            return $modules->where(function ($item) use ($id) {
                return $item->module_id == $id;
            })->first();
        } catch (Exception $ex) {
            Log::error('Module Load id="'.$id.'" Error', [$ex->getMessage()]);

            return null;
        }
    }

    public function remove($ids)
    {
        $result = [
            'flag' => false,
            'message' => '',
        ];
        DB::beginTransaction();
        try {
            $module = $this->repository->find($ids);
            if (count($module->roles) > 0) {
                $result['message'] = '该模块被角色拥有无法删除';
            } else {
                //删除模块
                $module->delete();
                $result['flag'] = true;
            }

            DB::commit();
        } catch (Exception $ex) {
            DB::rollBack();
            Log::error('Module Delete'.$ids.' Error', [$ex->getMessage()]);
        }

        return $result;
    }

    public function getTree()
    {
        $data = Traversable::from($this->repository->getRedisData());
        $data = $data->orderByAscending(function ($item) {
            return $item->sort_code;
        })->select(function ($item) {
            return [
                'id' => $item->module_id,
                'type' => 'module',
                'parent_id' => $item->parent_id,
                'label' => 'module_'.$item->module_id,
                'name' => $item->full_name,
                'route' => $item->url_address,
            ];
        })->asArray();

        return Tree::makeTree($data, ['expanded_key' => 'open']);
    }

    public function getManagerModels($manager)
    {
        $authorizeRepository = App('App\Repositories\Auth\AuthorizesRepository');
        $userRelationRepository = App('App\Repositories\Auth\UserRelationsRepository');

        $modules = Traversable::from($this->repository->getRedisData());
        $authorizes = Traversable::from($authorizeRepository->getRedisData());
        $userRelations = Traversable::from($userRelationRepository->getRedisData());

        $userAuthorize = $authorizes->join($userRelations)->on(function ($inner, $outer) use ($manager) {
            return  $inner->categorytable_id == $outer->categorytable_id && $inner->categorytable_type == $outer->categorytable_type && $outer->user_id == $manager->manager_id;
        })->to(function ($outer, $inner) {
            return (object) array(
                'categorytable_id' => $outer->categorytable_id,
                'categorytable_type' => $outer->categorytable_type,
                'itemtable_id' => $outer->itemtable_id,
                'itemtable_type' => $outer->itemtable_type,
            );
        });

        $data = $modules->orderByAscending(function ($item) {
            return $item->sort_code;
        })->join($userAuthorize)->on(function ($outer, $inner) {
            return $outer->module_id == $inner->itemtable_id;
        })->to(function ($outer, $inner) {
            return array(
               'id' => $outer->module_id,
               'type' => 'module',
               'parent_id' => $outer->parent_id,
               'label' => 'module_'.$outer->module_id,
               'name' => $outer->full_name,
               'route' => $outer->url_address,
               'sort_code' => $outer->sort_code,
            );
        })->asArray();

        $returnData = Tree::makeTree($data, ['expanded_key' => 'open']);

        return $returnData;
    }

    public function getManagerModelsHtml($manager)
    {
        $authorizeRepository = App('App\Repositories\Auth\AuthorizesRepository');
        $userRelationRepository = App('App\Repositories\Auth\UserRelationsRepository');

        $modules = Traversable::from($this->repository->getRedisData());
        $authorizes = Traversable::from($authorizeRepository->getRedisData());
        $userRelations = Traversable::from($userRelationRepository->getRedisData());

        $userAuthorize = $authorizes->join($userRelations)->on(function ($inner, $outer) use ($manager) {
            return  $inner->categorytable_id == $outer->categorytable_id && $inner->categorytable_type == $outer->categorytable_type && $outer->user_id == $manager->manager_id;
        })->to(function ($outer, $inner) {
            return (object) array(
                'categorytable_id' => $outer->categorytable_id,
                'categorytable_type' => $outer->categorytable_type,
                'itemtable_id' => $outer->itemtable_id,
                'itemtable_type' => $outer->itemtable_type,
            );
        });

        $menus = $modules->where(function ($item) {
            return $item->status;
        })->orderByAscending(function ($item) {
            return $item->sort_code;
        })->join($userAuthorize)->on(function ($outer, $inner) {
            return $outer->module_id == $inner->itemtable_id;
        })->to(function ($outer, $inner) {
            return $outer;
        });

        $data = $this->ModuleTree($menus);

        return $data;
    }

    protected function ModuleTree(Traversable $menus, string $parent_id = '', string $html = '')
    {
        $datas = $menus->where(function ($item) use ($parent_id) {
            return $item->parent_id == $parent_id;
        })->asTraversable();

        foreach ($datas as $item) {
            $html = $html.'<li class="layui-nav-item">';
            $html = $html.$this->createRoute($item);
            $html = $html.'<i class="layui-icon "'.$item->icon.'"></i>';
            $html = $html.'<cite>'.$item->full_name.'</cite>';
            $html = $html.'</a>';
            $html = $html.$this->createChild($menus, $item->module_id);
            $html = $html.'</li>';
        }

        return $html;
    }

    private function createRoute($item)
    {
        $href = '<a href="javascript:;"';
        if (null != $item->url_address || '' != $item->url_address) {
            if ('' != $item->params || null != $item->params) {
                $params = [];
                foreach (explode(';', $item->params) as $param) {
                    $it = explode(':', $param);
                    if (isset($it[1])) {
                        $params[$it[0]] = $it[1];
                    }
                }
                $route = route($item->url_address, $params);
            } else {
                $route = route($item->url_address);
            }
            $href = $href.'lay-href="'.$route.'"';
        }
        $href = $href.'" lay-tips="'.$item->full_name.'" lay-direction="2">';

        return $href;
    }

    private function createChild(Traversable $menus, $parent_id)
    {
        $html = '';
        $children = $menus->where(function ($data) use ($parent_id) {
            return $parent_id == $data->parent_id;
        })->asTraversable();
        foreach ($children as $child) {
            $html = $html.'<dl class="layui-nav-child">';
            $html = $html.'<dd data-name="'.$child->encode.'">';
            $html = $html.$this->createRoute($child);
            $html = $html.'<cite>'.$child->full_name.'</cite>';
            $html = $html.'</a>';
            $html = $html.$this->createChild($menus, $child->module_id, $html);
            $html = $html.'</dd>';
            $html = $html.'</dl>';
        }

        return $html;
    }
}
